home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1994 April / Inside Multimedia CD-ROM (April 1994).iso / prg / gs / gssource.exe / GS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  13.3 KB  |  476 lines

  1. /* Copyright (C) 1989, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gs.c */
  21. /* Driver program for Ghostscript */
  22. #include <ctype.h>
  23. #include "memory_.h"
  24. #include "string_.h"
  25. /* Capture stdin/out/err before gs.h redefines them. */
  26. #include <stdio.h>
  27. static FILE *real_stdin, *real_stdout, *real_stderr;
  28. static void
  29. get_real()
  30. {    real_stdin = stdin, real_stdout = stdout, real_stderr = stderr;
  31. }
  32. /* Define PROGRAM_NAME before we include std.h */
  33. #ifndef PROGRAM_NAME
  34. #  define PROGRAM_NAME "Ghostscript"
  35. #endif
  36. #include "ghost.h"
  37. #include "gxdevice.h"
  38. #include "gxdevmem.h"
  39. #include "alloc.h"
  40. #include "errors.h"
  41. #include "estack.h"
  42. #include "main.h"
  43. #include "ostack.h"
  44. #include "store.h"
  45. #include "stream.h"
  46.   
  47. #ifndef GS_LIB
  48. #  define GS_LIB "GS_LIB"
  49. #endif
  50.  
  51. /* Library routines not declared in a standard header */
  52. extern char *getenv(P1(const char *));
  53. /* Note: sscanf incorrectly defines its first argument as char * */
  54. /* rather than const char *.  This accounts for the ugly casts below. */
  55.  
  56. /* Device procedures imported from gsdevice.c. */
  57. extern gx_device *gs_getdevice(P1(int));
  58. extern char *gs_devicename(P1(gx_device *));
  59.  
  60. /* Other imported data */
  61. extern int gs_alloc_debug;
  62. extern int gs_log_errors;
  63. extern gx_device *gx_device_list[];
  64.  
  65. /*
  66.  * Help strings.  We have to break them up into parts, because
  67.  * the Watcom compiler has a limit of 510 characters for a single token.
  68.  * For PC displays, we want to limit the strings to 24 lines.
  69.  */
  70. private const char *gs_help1 = "\
  71. Usage: gs [switches] [file1.ps file2.ps ...]\n\
  72.   or : gs [switches] [file1.ps ...] -- filen.ps arg1 arg2 ...\n\
  73. The latter passes arg1 ... to the program in filen.ps.\n\
  74. Available devices:\n   ";
  75. /* We have to break help2 up into parts, because  */
  76. private const char *gs_help2a = "\n\
  77. Switches: (you can use # in place of =)\n\
  78.     @<file>              treat file like part of the command line\n\
  79.                            (to get around DOS command line limit)\n\
  80.     -d<name>[=<token>]   define name as token, or null if no token given\n\
  81.     -f<file>             read this file even if its name begins with - or @\n";
  82. private const char *gs_help2b = "\
  83.     -g<width>x<height>   set width and height (`geometry'), in pixels\n\
  84.     -I<prefix>           add prefix to search path\n\
  85.     -q                   `quiet' mode, suppress most messages\n\
  86.     -r<res>              set resolution, in pixels per inch\n";
  87. private const char *gs_help2c = "\
  88.     -s<name>=<string>    define name as string\n\
  89.     -sDEVICE=<devname>   select initial device\n\
  90.     -sOutputFile=<file>  select output file: embed %d for page #,\n\
  91.                            - means stdout, use |command to pipe\n\
  92. `-' alone as a file name means read from stdin non-interactively.\n\
  93. For more information, please read the use.doc file.\n";
  94.  
  95. /* Forward references */
  96. private int swproc(P1(const char *));
  97. private void argproc(P1(const char *));
  98. private void cmdproc(P1(const char *));
  99. private int esc_strlen(P1(const char *));
  100. private void esc_strcat(P2(char *, const char *));
  101. private void runarg(P4(const char **, const char *, const char *, int));
  102. private void run_string(P1(const char *));
  103.  
  104. /* Parameters set by swproc */
  105. private int quiet;
  106. private int batch;
  107.  
  108. main(int argc, const char *argv[])
  109. {    int argi;
  110.     get_real();
  111.     gs_init0(real_stdin, real_stdout, real_stderr, argc);
  112.        {    char *lib = getenv(GS_LIB);
  113.         if ( lib != 0 ) 
  114.            {    int len = strlen(lib);
  115.             gs_lib_env_path = gs_malloc(len + 1, 1, "GS_LIB");
  116.             strcpy(gs_lib_env_path, lib);
  117.            }
  118.        }
  119.     /* Execute files named in the command line, */
  120.     /* processing options along the way. */
  121.     /* Wait until the first file name (or the end */
  122.     /* of the line) to finish initialization. */
  123.     batch = 0;
  124.     quiet = 0;
  125.     /* If debugging is enabled, trace the device calls. */
  126. #ifdef DEBUG
  127.        {    extern gx_device *gs_trace_device(P1(gx_device *));
  128.         extern const gx_device_memory
  129.             mem_mono_device, mem_mapped2_color_device,
  130.             mem_mapped4_color_device, mem_mapped8_color_device,
  131.             mem_true16_color_device,
  132.             mem_true24_color_device, mem_true32_color_device;
  133.         static const gx_device_memory *mdevs[8] =
  134.            {    &mem_mono_device, &mem_mapped2_color_device,
  135.             &mem_mapped4_color_device, &mem_mapped8_color_device,
  136.             &mem_true16_color_device,
  137.             &mem_true24_color_device, &mem_true32_color_device,
  138.             0
  139.            };
  140.         extern gx_device gs_clist_device;    /* gx_clist_device */
  141.         static gx_device *cldevs[2] =
  142.            {    &gs_clist_device,
  143.             0
  144.            };
  145.         gx_device **pdevs[4];
  146.         gx_device ***ppdev;
  147.         gx_device **pdev;
  148.         pdevs[0] = gx_device_list;
  149.         pdevs[1] = (gx_device **)mdevs;
  150.         pdevs[2] = cldevs;
  151.         pdevs[3] = 0;
  152.         for ( ppdev = pdevs; *ppdev != 0; ppdev++ )
  153.          for ( pdev = *ppdev; *pdev != 0; pdev++ )
  154.            {
  155. /******
  156.             gx_device *tdev = gs_trace_device(*pdev);
  157.             if ( tdev == 0 )
  158.                {    lprintf("Can't allocate traced device!\n");
  159.                 gs_exit(1);
  160.                }
  161.             *pdev = tdev;
  162.  ******/
  163.            }
  164.        }
  165. #endif
  166.     for ( argi = 1; argi < argc; argi++ )
  167.        {    const char **argp = &argv[argi];
  168.         const char *arg = *argp;
  169.         switch ( *arg )
  170.         {
  171.         case '@':
  172.             cmdproc(arg);
  173.             break;
  174.         case '-':
  175.             if ( !strcmp(arg, "--") || !strcmp(arg, "-+") )
  176.             {    /* run with command line args */
  177.                 int nstrs = argc - argi - 2;
  178.                 if ( nstrs < 0 )    /* no file to run! */
  179.                 {    puts("Usage: gs ... -- file.ps arg1 ... argn");
  180.                     gs_exit(1);
  181.                 }
  182.                 runarg(argp + 1, "{userdict /ARGUMENTS [", "] put (", nstrs);
  183.                 gs_exit(0);
  184.             }
  185.             else
  186.             {    if ( swproc(arg) < 0 )
  187.                   fprintf(stdout, "Unknown switch %s - ignoring\n", arg);
  188.             }
  189.             break;
  190.         default:
  191.             argproc(arg);
  192.         }
  193.        }
  194.     gs_init2();
  195.     if ( !batch ) run_string("start");
  196.     gs_exit(0);
  197. }
  198.  
  199. /* Process switches */
  200. private int
  201. swproc(const char *arg)
  202. {    char sw = arg[1];
  203.     arg += 2;        /* skip - and letter */
  204.     switch ( sw )
  205.        {
  206.     default:
  207.         return -1;
  208.     case 0:                /* read stdin as a file */
  209.         batch = 1;
  210.         /* Set NOPAUSE so showpage won't try to read from stdin. */
  211.         swproc("-dNOPAUSE");
  212.         gs_init2();        /* Finish initialization */
  213.         run_string("(%stdin) (r) file cvx execute");
  214.         break;
  215.     case 'A':            /* trace allocator */
  216.         gs_alloc_debug = 1; break;
  217.     case 'e':            /* log errors */
  218.         gs_log_errors = 1; break;
  219.     case 'E':            /* log errors */
  220.         gs_log_errors = 2; break;
  221.     case 'f':            /* run file of arbitrary name */
  222.         argproc(arg); break;
  223.     case 'h':            /* print help */
  224.     case '?':            /* ditto */
  225.         fputs(gs_help1, stdout);
  226.            {    int i;
  227.             gx_device *pdev;
  228.             for ( i = 0; (pdev = gs_getdevice(i)) != 0; i++ )
  229.                 fprintf(stdout, " %s", gs_devicename(pdev));
  230.            }
  231.         fputs(gs_help2a, stdout);
  232.         fputs(gs_help2b, stdout);
  233.         fputs(gs_help2c, stdout);
  234.         gs_exit(0);
  235.     case 'I':            /* specify search path */
  236.         gs_add_lib_path(arg);
  237.         break;
  238.     case 'q':            /* quiet startup */
  239.        {    ref vtrue;
  240.         quiet = 1;
  241.         gs_init1();
  242.         make_true(&vtrue);
  243.         initial_enter_name("QUIET", &vtrue);
  244.        }    break;
  245.     case 'D':            /* define name */
  246.     case 'd':
  247.     case 'S':            /* define name as string */
  248.     case 's':
  249.        {    char *eqp = strchr(arg, '=');
  250.         int isd = (sw == 'D' || sw == 'd');
  251.         ref value;
  252.         if ( eqp == NULL ) eqp = strchr(arg, '#');
  253.         /* Initialize the object memory, scanner, and */
  254.         /* name table now if needed. */
  255.         gs_init1();
  256.         if ( eqp == arg )
  257.            {    puts("Usage: -dname, -dname=token, -sname=string");
  258.             gs_exit(1);
  259.            }
  260.         if ( eqp == NULL )
  261.            {    if ( isd ) make_null(&value);
  262.             else make_tasv(&value, t_string, a_readonly,
  263.                        0, bytes, (byte *)"");
  264.            }
  265.         else
  266.            {    int code;
  267.             *eqp++ = 0;    /* delimit name */
  268.             if ( isd )
  269.                {    stream astream;
  270.                 sread_string(&astream,
  271.                          (byte *)eqp, strlen(eqp));
  272.                 code = scan_token(&astream, 0, &value);
  273.                 if ( code )
  274.                    {    puts("-dname= must be followed by a valid token");
  275.                     gs_exit(1);
  276.                    }
  277.                }
  278.             else
  279.                {    int len = strlen(eqp);
  280.                 char *str = gs_malloc((uint)len, 1, "-s");
  281.                 if ( str == 0 )
  282.                    {    lprintf("Out of memory!\n");
  283.                     gs_exit(1);
  284.                    }
  285.                 memcpy(str, eqp, len);
  286.                 make_tasv(&value, t_string, a_readonly,
  287.                       len, bytes, (byte *)str);
  288.                }
  289.            }
  290.         /* Enter the name in systemdict */
  291.         initial_enter_name(arg, &value);
  292.         break;
  293.        }
  294.     case 'g':            /* define device geometry */
  295.        {    long width, height;
  296.         ref value;
  297.         gs_init1();
  298.         if ( sscanf((char *)arg, "%ldx%ld", &width, &height) != 2 )
  299.            {    puts("-g must be followed by <width>x<height>");
  300.             gs_exit(1);
  301.            }
  302.         make_int(&value, width);
  303.         initial_enter_name("DEVICEWIDTH", &value);
  304.         make_int(&value, height);
  305.         initial_enter_name("DEVICEHEIGHT", &value);
  306.         break;
  307.        }
  308.     case 'M':            /* set memory allocation increment */
  309.        {    unsigned msize = 0;
  310.         sscanf((char *)arg, "%d", &msize);
  311.         if ( msize <= 0 || msize >= 64 )
  312.            {    puts("-M must be between 1 and 63");
  313.             gs_exit(1);
  314.            }
  315.         gs_memory_chunk_size = msize << 10;
  316.        }
  317.         break;
  318.     case 'r':            /* define device resolution */
  319.        {    float xres, yres;
  320.         ref value;
  321.         gs_init1();
  322.         switch ( sscanf((char *)arg, "%fx%f", &xres, &yres) )
  323.            {
  324.         default:
  325.             puts("-r must be followed by <res> or <xres>x<yres>");
  326.             gs_exit(1);
  327.         case 1:            /* -r<res> */
  328.             yres = xres;
  329.         case 2:            /* -r<xres>x<yres> */
  330.             make_real(&value, xres);
  331.             initial_enter_name("DEVICEXRESOLUTION", &value);
  332.             make_real(&value, yres);
  333.             initial_enter_name("DEVICEYRESOLUTION", &value);
  334.            }
  335.         break;
  336.        }
  337.     case 'Z':
  338.         if ( !*arg )
  339.            {    /* No options, set all flags */
  340.             memset(gs_debug, 0xff, 128);
  341.            }
  342.         else
  343.            {    while ( *arg )
  344.                 gs_debug[*arg++ & 127] = 0xff;
  345.            }
  346.         break;
  347.        }
  348.     return 0;
  349. }
  350.  
  351. /* Define versions of strlen and strcat that insert \ escapes */
  352. /* before \, (, and ). */
  353. #define needs_esc(ch) ((ch) == '(' || (ch) == ')' || (ch) == '\\')
  354. private int
  355. esc_strlen(const char *str)
  356. {    int n = strlen(str);
  357.     const char *p;
  358.     for ( p = str; *p; p++ ) if ( needs_esc(*p) ) n++;
  359.     return n;
  360. }
  361. private void
  362. esc_strcat(char *dest, const char *src)
  363. {    char *d = dest + strlen(dest);
  364.     const char *p;
  365.     for ( p = src; *p; p++ )
  366.        {    if ( needs_esc(*p) ) *d++ = '\\';
  367.         *d++ = *p;
  368.        }
  369.     *d = 0;
  370. }
  371.  
  372. /* Process file names */
  373. private void
  374. argproc(const char *arg)
  375. {    runarg(&arg, "{", "(", 0);
  376. }
  377. private void
  378. runarg(const char **argp, const char *pre, const char *post, int nstrs)
  379. {    const char *arg = *argp;
  380.     static const char *pex = ")run}execute";
  381.     int len = strlen(pre) + esc_strlen(arg) + nstrs * 2 + strlen(post) + strlen(pex) + 1;
  382.     char *line;
  383.     int i;
  384.     for ( i = 1; i <= nstrs; i++ )
  385.         len += esc_strlen(argp[i]) + 2;
  386.     gs_init2();    /* Finish initialization */
  387.     line = gs_malloc(len, 1, "argproc");
  388.     if ( line == 0 )
  389.     {    lprintf("Out of memory!\n");
  390.         gs_exit(1);
  391.     }
  392.     strcpy(line, pre);
  393.     for ( i = 1; i <= nstrs; i++ )
  394.        {    strcat(line, "(");
  395.         esc_strcat(line, argp[i]);
  396.         strcat(line, ")");
  397.        }
  398.     strcat(line, post);
  399.     esc_strcat(line, arg);
  400.     strcat(line, pex);
  401.     run_string(line);
  402. }
  403. private void
  404. run_string(const char *str)
  405. {    int exit_code;
  406.     int code = gs_run_string(str, gs_user_errors, &exit_code);
  407.     zflush((ref *)0);    /* flush stdout */
  408.     zflushpage((ref *)0); /* force display update */
  409.     switch ( code )
  410.     {
  411.     case 0:
  412.         break;
  413.     case e_Quit:
  414.         gs_exit(0);
  415.     case e_Fatal:
  416.         eprintf1("Unrecoverable error, exit code %d\n", exit_code);
  417.         gs_exit(exit_code);
  418.     default:
  419.         gs_debug_dump_stack(code);
  420.         gs_exit(255);
  421.     }
  422. }
  423.  
  424. /* Process command line indirection. */
  425. private void
  426. cmdproc(const char *arg)
  427. {    FILE *f;
  428. #define cstr_max 128
  429.     char cstr[cstr_max + 1];
  430.     arg++;        /* skip over @ */
  431.     f = fopen(arg, "r");
  432.     if ( f == NULL )
  433.     {    fprintf(stdout, "Unable to open command line file %s\n", arg);
  434.         gs_exit(1);
  435.     }
  436.     while ( 1 )
  437.     {    register int c;
  438.         register int i;
  439.         while ( isspace(c = fgetc(f)) ) ;
  440.         if ( c == EOF ) break;
  441.         for ( i = 0; ; )
  442.         {    if ( i == cstr_max )
  443.             {    cstr[i] = 0;
  444.                 fprintf(stdout, "Command too long: %s\n", cstr);
  445.                 gs_exit(1);
  446.             }
  447.             cstr[i++] = c;
  448.             c = fgetc(f);
  449.             if ( c == EOF || isspace(c) )
  450.                 break;
  451.         }
  452.         cstr[i] = 0;
  453.         switch ( cstr[0] )
  454.         {
  455.         case '@':
  456.             cmdproc(cstr);
  457.             break;
  458.         case '-':
  459.         {    /* swproc wants strings to be in the heap! */
  460.             char *sstr = gs_malloc(i + 1, 1, "cmdproc");
  461.             if ( sstr == 0 )
  462.             {    lprintf("Out of memory!\n");
  463.                 gs_exit(1);
  464.             }
  465.             strcpy(sstr, cstr);
  466.             if ( swproc(sstr) < 0 )
  467.               fprintf(stdout, "Unknown switch %s - ignoring\n", sstr);
  468.         }
  469.             break;
  470.         default:
  471.             argproc(cstr);
  472.         }
  473.     }
  474.     fclose(f);
  475. }
  476.